/**
*
* @file
*		heap_dmk
*
* @brief
*		Heap implementation by dm_karpov
*/
#include <Windows.h>
#include "../../api/heap.h"
#include <stdio.h>
#include <vector>

using namespace std;

#ifndef __HEAP_DMK_H__
#define __HEAP_DMK_H__

#define TLSF 1

#define Err printf
#define NALLOC 1024   // Minimal demanded number of blocks

#define POISON_ALLOC 0xDEADBA00//debug poison for allocated pieces
#define POISON_FREE  0xAAADBA00//debug poison for free pieces

/**
* basic interface
*/
class heap_dmk : public heap876
{

private:

	typedef double Align;  // Alignment of the boundary of double

	union header {		// Header of the block
		struct {
			union header *ptr;	//Next block if existed
			unsigned size;		//Size of this block
		} s;
		Align x;			// forced alignment of blocks
	};

	typedef union header Header;

	 Header base;  // An empty list for the beginning
	 Header *freep; //pointer to last founded block
	 int total_limit;
	 int count1; // How many times allocator calls OS to give memory
	 int count;		// Amount of distributed memory
		 	 	 	 
	 // Demand additional memory from the OS
	 Header* morecore(size_t nu)
	 {
		count1++;
		char *cp;
		Header *up;

		if (nu < NALLOC)
			nu = NALLOC;
		count += nu * sizeof(Header);
		if (count  > total_limit)
		{
			if  (count1 == 1) 
			{
				Err("total = %d it is not enough, enter > %d\n", total_limit,  NALLOC * sizeof(Header));
				return NULL;
			}
			count -= nu * sizeof(Header);
			Err ("Error: failed to alloc\nAmount of memory order from the OS = %d\nTotal amount of distributed memory = %d\n", --count1, count);
			return NULL;
		}
		cp = new char[nu * sizeof(Header)];
		if (cp == NULL)
			return NULL;
		up = (Header *) cp;
		up ->s.size = nu;
		free((void *)(up + 1));
		return freep;
	 }

public:

	heap_dmk( size_t total, alloc_flags flag)  : heap876(total, flag, "dm_karpov")
	{
#ifdef TLSF
		printf("This is tlsf based allocator, if you want nextfit algorithm undef TLSF in head_dmk.h\n");
		if (total == 0)
		{
			printf("\nError: Don't set all memory equals to 0\n");
			exit(0);
		}
		pool = malloc(total);
		tlsf_create(pool , total);
#else
		printf("This is nextfit allocator, if you want tlsf algorithm define TLSF in head_dmk.h\n");
		total_limit = total;
		freep = NULL;
		count = 0;
		count1 = 0;
#endif
	};  
	void* pool;
	virtual ~heap_dmk() { tlsf_destroy(pool); };
	virtual void*	alloc( size_t sz, unsigned int tag = 0 );
	virtual void	free( void* ptr );
	virtual void	free_all( unsigned int tag );
	virtual size_t get_occupancy() const;

	void* nextfit_alloc(size_t sz, unsigned int tag = 0 );
	void nextfit_free(void* ptr);

	void* tlsf_create(void* pool, size_t size);
	void tlsf_destroy(void* pool);
#ifdef _DEBUG
	void all_blocks_info (char *block_ptr); 
	void free_blocks_info (char *block_ptr);
#endif
	void Print()
	{
		Header* p;
		int i = 0;
		if (freep == NULL)
			return;
		p = freep->s.ptr;
		printf("\nFree blocks:\n");
		while(p != freep)
		{
			printf ("Free block size = %d bytes\n", p->s.size * sizeof(Header));
			p = p->s.ptr;
			i++;
		}
		printf("\nAmount of free blocks = %d\n", i);
	}
	vector <void *> not_free;  // addresses of not free blocks
};


#endif//__HEAP_DMK_H__